package com.yanqu.road.server.manger.activity.tripletown;

import com.yanqu.road.entity.activity.tripletown.Block;
import com.yanqu.road.entity.activity.tripletown.EliminateRoundResult;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AddBombLogic {

    /**
     * 添加炸弹
     */
    public static void addBomb(int fromX, int fromY, int toX, int toY, int round,
                               Map<Integer, Map<Integer, Block>> eliminateMap,
                               Map<Integer, Map<Integer, Block>> dropMap,
                               int[][] copyBlockList, EliminateRoundResult roundResult) {

        List<Block> newBombList = new ArrayList<>();

        Map<Integer, List<List<Block>>> mapListList = groupSortSameColor(eliminateMap);

        // 【分组生成炸弹】
        for (List<List<Block>> listList : mapListList.values()) {
            for (int i = 0; i < 100 && listList.size() > 0; i++) { // 假装是 while
                List<Block> list = listList.remove(listList.size() - 1); // 每次拿最后一组
                if (list.size() < 4) continue;

                // 转map
                Map<Integer, Map<Integer, Block>> tmpMapMap = new ConcurrentHashMap<>();
                for (int j = 0; j < copyBlockList.length; j++) tmpMapMap.put(j, new ConcurrentHashMap<>());
                for (Block block : list) tmpMapMap.get(block.getY()).put(block.getX(), block);

                // 多行5个
                newBombList.addAll(createX(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 5, true, 10));
                newBombList.addAll(createY(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 5, true, 10));

                // 多行4个
                newBombList.addAll(createX(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 4, true, 9));
                newBombList.addAll(createY(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 4, true, 9));

                int size = newBombList.size();

                // 单行5个
                newBombList.addAll(createX(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 5, false, 10));
                newBombList.addAll(createY(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 5, false, 10));
                if (size != newBombList.size()) {
                    listList.add(list); // 剩下的下一轮
                    continue;
                }

                // T型
                newBombList.addAll(createT(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap));
                if (size != newBombList.size()) {
                    listList.add(list); // 剩下的下一轮
                    continue;
                }

                // 单行4个
                newBombList.addAll(createX(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 4, false, 9));
                newBombList.addAll(createY(fromX, fromY, toX, toY, round, dropMap, copyBlockList, list, tmpMapMap, 4, false, 9));
                if (size != newBombList.size()) {
                    listList.add(list); // 剩下的下一轮
                    continue;
                }
            }
        }

        // 【添加到每轮结果】
        for (Block block : newBombList) {
            copyBlockList[block.getY()][block.getX()] = block.getC();
            roundResult.getCreateBomb().add(block);
        }
    }

    /**
     * 计算炸弹生成下标
     */
    private static Block createBombBlock(int round, int fromX, int fromY, int toX, int toY, int type,
                                              List<Block> list, Map<Integer, Map<Integer, Block>> dropMap) {
        // 指定炸弹生成位置
        Block coreBlock = null;
        if (round == 1) {
            for (Block Block : list) {
                if (Block.getX() == toX && Block.getY() == toY) {
                    coreBlock = Block;
                    break;
                }
                if (Block.getX() == fromX && Block.getY() == fromY) {
                    coreBlock = Block;
                }
            }
        }
        if (coreBlock != null) {
            return new Block(coreBlock.getX(), coreBlock.getY(), type);
        }

        // 下落点判断
        int x = Integer.MAX_VALUE;
        int y = Integer.MAX_VALUE;
        for (Block block : list) {
            if (dropMap.get(block.getY()).containsKey(block.getX())) {
                if (x == Integer.MAX_VALUE || y == Integer.MAX_VALUE) {
                    x = block.getX();
                    y = block.getY();
                } else {
                    if (block.getY() == y) {
                        if (block.getX() < x) {
                            x = block.getX();
                            y = block.getY();
                        }
                    } else {
                        if (block.getY() < y) {
                            x = block.getX();
                            y = block.getY();
                        }
                    }
                }
            }
        }

        // 还没有就返回最小下标
        if (x == Integer.MAX_VALUE || y == Integer.MAX_VALUE) {
            return new Block(list.get(0).getX(), list.get(0).getY(), type);
        } else {
            return new Block(x, y, type);
        }
    }

    /**
     * 相同颜色分组排序（不含被炸弹炸的）
     *
     * @return Map<颜色 ， List < 每组数据>>
     */
    private static Map<Integer, List<List<Block>>> groupSortSameColor(Map<Integer, Map<Integer, Block>> eliminateMap) {
        // 【自然消除的分组】
        Map<Integer, List<List<Block>>> mapListList = new ConcurrentHashMap<>();
        for (Map<Integer, Block> blockMap : eliminateMap.values()) {
            for (Block block : blockMap.values()) {
                if (EliminateLogic.isBomb(block.getC()) || !block.isEliminate()) {
                    continue;
                }
                if (!mapListList.containsKey(block.getC())) {
                    mapListList.put(block.getC(), new ArrayList<>());
                }

                List<List<Block>> listList = mapListList.get(block.getC());
                List<Integer> adjoinIndexList = new ArrayList<>();
                for (int i = 0; i < listList.size(); i++) {
                    List<Block> list = listList.get(i);
                    for (Block Block : list) {
                        if (Block.getC() == block.getC() && isBlockAdjoin(Block, block)) {
                            adjoinIndexList.add(i);
                            break;
                        }
                    }
                }

                List<Block> list = new ArrayList<>();
                list.add(block);
                for (Integer index : adjoinIndexList) {
                    list.addAll(listList.get(index));
                }
                for (int i = adjoinIndexList.size() - 1; i >= 0; i--) {
                    listList.remove((int) adjoinIndexList.get(i));
                }
                listList.add(list);
            }
        }

        // 【每组小到大排序】
        for (List<List<Block>> value : mapListList.values()) {
            for (List<Block> blockList : value) {
                blockList.sort(new Comparator<Block>() {
                    @Override
                    public int compare(Block o1, Block o2) {
                        if (o1.getY() != o2.getY()) {
                            return o1.getY() - o2.getY();
                        } else if (o1.getX() != o2.getX()) {
                            return o1.getX() - o2.getX();
                        } else {
                            return 0;
                        }
                    }
                });
            }
        }
        return mapListList;
    }

    /**
     * 方块是否相邻
     */
    private static boolean isBlockAdjoin(Block block1, Block block2) {
        int subY = Math.abs(block1.getY() - block2.getY());
        int subX = Math.abs(block1.getX() - block2.getX());
        return subY == 1 && subX == 0 || subY == 0 && subX == 1;
    }

    // =================================    匹配炸弹形状    =================================

    private static List<Block> createY(int fromX, int fromY, int toX, int toY, int round,
                                            Map<Integer, Map<Integer, Block>> dropMap,
                                            int[][] copyBlockList, List<Block> list,
                                            Map<Integer, Map<Integer, Block>> tmpMapMap,
                                            int continueCount, boolean multi, int bombType) {
        List<List<Block>> groupLineList = new ArrayList<>();
        Map<Integer, Map<Integer, Block>> hadCheckMap = new ConcurrentHashMap<>();
        for (int tmpY = 0; tmpY < copyBlockList.length; tmpY++)
            hadCheckMap.put(tmpY, new ConcurrentHashMap<>());
        for (Block block : list) {
            if (hadCheckMap.get(block.getY()).containsKey(block.getX())) continue;
            hadCheckMap.get(block.getY()).put(block.getX(), block);
            List<Block> tmpList = new ArrayList<>();
            tmpList.add(block);
            for (int y = block.getY() + 1; y < copyBlockList.length && y < block.getY() + continueCount; y++) {
                Block tmpBlock = tmpMapMap.get(y).get(block.getX());
                if (tmpBlock != null) {
                    tmpList.add(tmpBlock);
                    hadCheckMap.get(tmpBlock.getY()).put(tmpBlock.getX(), tmpBlock);
                } else break;
            }
            if (tmpList.size() == continueCount) groupLineList.add(tmpList);
        }
        List<Block> bombList = new ArrayList<>();
        if (multi && groupLineList.size() > 1 ||
                !multi && groupLineList.size() == 1) {
            for (List<Block> useList : groupLineList) {
                for (Block block : useList) {
                    // 计算生成位置
                    bombList.add(createBombBlock(round, fromX, fromY, toX, toY, bombType, useList, dropMap));
                    // map移除方块
                    tmpMapMap.get(block.getY()).remove(block.getX());
                    // list移除方块
                    list.remove(block);
                }
            }
        }
        return bombList;
    }

    private static List<Block> createX(int fromX, int fromY, int toX, int toY, int round,
                                            Map<Integer, Map<Integer, Block>> dropMap,
                                            int[][] copyBlockList, List<Block> list,
                                            Map<Integer, Map<Integer, Block>> tmpMapMap,
                                            int continueCount, boolean multi, int bombType) {
        List<List<Block>> groupLineList = new ArrayList<>();
        Map<Integer, Map<Integer, Block>> hadCheckMap = new ConcurrentHashMap<>();
        for (int tmpY = 0; tmpY < copyBlockList.length; tmpY++)
            hadCheckMap.put(tmpY, new ConcurrentHashMap<>());
        for (Block block : list) {
            if (hadCheckMap.get(block.getY()).containsKey(block.getX())) continue;
            hadCheckMap.get(block.getY()).put(block.getX(), block);
            List<Block> tmpList = new ArrayList<>();
            tmpList.add(block);
            for (int x = block.getX() + 1; x > 0 && x < block.getX() + continueCount; x++) {
                Block tmpBlock = tmpMapMap.get(block.getY()).get(x);
                if (tmpBlock != null) {
                    tmpList.add(tmpBlock);
                    hadCheckMap.get(tmpBlock.getY()).put(tmpBlock.getX(), tmpBlock);
                } else break;
            }
            if (tmpList.size() == continueCount) groupLineList.add(tmpList);
        }
        List<Block> bombList = new ArrayList<>();
        if (multi && groupLineList.size() > 1 ||
                !multi && groupLineList.size() == 1) {
            for (List<Block> useList : groupLineList) {
                for (Block block : useList) {
                    // 计算生成位置
                    bombList.add(createBombBlock(round, fromX, fromY, toX, toY, bombType, useList, dropMap));
                    // map移除方块
                    tmpMapMap.get(block.getY()).remove(block.getX());
                    // list移除方块
                    list.remove(block);
                }
            }
        }
        return bombList;
    }

    private static List<Block> createT(int fromX, int fromY, int toX, int toY, int round,
                                            Map<Integer, Map<Integer, Block>> dropMap,
                                            int[][] copyBlockList, List<Block> list,
                                            Map<Integer, Map<Integer, Block>> tmpMapMap) {
        List<List<Block>> groupLineList = new ArrayList<>();
        Map<Integer, Map<Integer, Block>> hadCheckMap = new ConcurrentHashMap<>();
        for (int tmpY = 0; tmpY < copyBlockList.length; tmpY++)
            hadCheckMap.put(tmpY, new ConcurrentHashMap<>());
        for (Block block : list) {
            if (hadCheckMap.get(block.getY()).containsKey(block.getX())) continue;
            List<Block> tmpList = new ArrayList<>();
            tmpList.add(block);

            for (int y = block.getY() - 1; y >= 0 && tmpList.size() < 3; y--) {
                Block tmpBlock = tmpMapMap.get(y).get(block.getX());
                if (tmpBlock != null && !hadCheckMap.get(tmpBlock.getY()).containsKey(tmpBlock.getX())) {
                    tmpList.add(tmpBlock);
                } else break;
            }
            for (int y = block.getY() + 1; y < copyBlockList.length && tmpList.size() < 3; y++) {
                Block tmpBlock = tmpMapMap.get(y).get(block.getX());
                if (tmpBlock != null && !hadCheckMap.get(tmpBlock.getY()).containsKey(tmpBlock.getX())) {
                    tmpList.add(tmpBlock);
                } else break;
            }
            if (tmpList.size() < 3) continue; // 无法生成
            for (int x = block.getX() - 1; x >= 0 && tmpList.size() < 5; x--) {
                Block tmpBlock = tmpMapMap.get(block.getY()).get(x);
                if (tmpBlock != null && !hadCheckMap.get(tmpBlock.getY()).containsKey(tmpBlock.getX())) {
                    tmpList.add(tmpBlock);
                } else break;
            }
            for (int x = block.getX() + 1; x < copyBlockList[0].length && tmpList.size() < 5; x++) {
                Block tmpBlock = tmpMapMap.get(block.getY()).get(x);
                if (tmpBlock != null && !hadCheckMap.get(tmpBlock.getY()).containsKey(tmpBlock.getX())) {
                    tmpList.add(tmpBlock);
                } else break;
            }
            if (tmpList.size() == 5) {
                groupLineList.add(tmpList);
                for (Block Block : tmpList) {
                    hadCheckMap.get(Block.getY()).put(Block.getX(), Block);
                }
            }
        }
        List<Block> bombList = new ArrayList<>();
        if (!groupLineList.isEmpty()) {
            for (List<Block> useList : groupLineList) {
                // 计算生成位置
                bombList.add(createBombBlock(round, fromX, fromY, toX, toY, 10, useList, dropMap));
                for (Block block : useList) {
                    // map移除方块
                    tmpMapMap.get(block.getY()).remove(block.getX());
                    // list移除方块
                    list.remove(block);
                }
            }
        }
        return bombList;
    }
}
